#pragma once
#include <iostream>
#include <fstream>
#include <string>
#include <cstring>
#include <vector>
#include <sqlite3.h>
#include <random>
#include <atomic>
#include <sstream>
#include "Log.hpp"
#include <iomanip>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
using namespace std;
namespace mq
{
    class SqliteHelper
    {
        typedef int (*sqlite_callback)(void *, int, char **, char **);

    public:
        SqliteHelper(const string &filename)
            : _db_filename(filename), _db_handler(nullptr)
        {
        }
        // 打开数据库文件
        bool open(int level = SQLITE_OPEN_FULLMUTEX)
        {
            int ret = sqlite3_open_v2(_db_filename.c_str(), &_db_handler, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | level, nullptr);
            if (ret != SQLITE_OK)
            {
                DLOG("数据库文件创建/打开失败:%s", sqlite3_errmsg(_db_handler));
                return false;
            }
            return true;
        }
        // 执行sql语句
        bool exec(const string &sql, sqlite_callback callback, void *arg)
        {
            int ret = sqlite3_exec(_db_handler, sql.c_str(), callback, arg, nullptr);
            if (ret != SQLITE_OK)
            {
                cout << sql << endl;
                DLOG("数据库操作失败:%s", sqlite3_errmsg(_db_handler));
                return false;
            }
            return true;
        }
        // 关闭数据库连接
        void close()
        {
            if (_db_handler)
                sqlite3_close(_db_handler);
        }

    private:
        string _db_filename;
        sqlite3 *_db_handler;
    };

    class StringHelper
    {
    public:
        // 分割字符串并传出arry
        static size_t splite(const string &str, const string &sep, vector<string> &arry)
        {
            if (str.empty() || sep.empty())
                return 0;
            size_t pos = 0, idx = 0;
            while (idx < str.size())
            {
                pos = str.find(sep, idx);
                if (pos == string::npos)
                {
                    arry.push_back(str.substr(idx));
                    break;
                }
                if (idx == pos)
                {
                    idx += sep.size();
                    continue;
                }
                arry.push_back(str.substr(idx, pos - idx));
                idx = pos + sep.size();
            }
            return arry.size();
        }
    };

    class UuidHelper
    {
    public:
        // 生成唯一标识符
        static string uuid()
        {
            random_device rd;
            mt19937_64 gernator(rd());
            uniform_int_distribution<int> distribution(0, 255);
            std::stringstream ss;
            for (int i = 0; i < 8; ++i)
            {
                ss << hex << setw(2) << setfill('0') << distribution(gernator);
                if (i == 3 || i == 5 || i == 7)
                    ss << "-";
            }
            static atomic<size_t> seq(1);
            size_t num = seq.fetch_add(1);
            for (int i = 7; i >= 0; --i)
            {
                ss << hex << setw(2) << setfill('0') << ((num >> i * 8) & 0xff);
                if (i == 6)
                    ss << "-";
            }
            return ss.str();
        }
    };
    class FileHelper
    {
    public:
        FileHelper(const string &filename) : _filename(filename) {}
        // 判断文件是否存在
        bool exists()
        {
            struct stat st;
            return (stat(_filename.c_str(), &st) == 0);
        }
        // 获取文件大小
        size_t size()
        {
            struct stat st;
            if (stat(_filename.c_str(), &st) < 0)
                return 0;
            return st.st_size;
        }
        // 从文件中读取数据
        bool read(char *body, size_t offset, size_t len)
        {
            ifstream ifs(_filename, ios::binary | ios::in);
            if (ifs.is_open() == false)
            {
                DLOG("文件打开失败: %s", strerror(errno));
                return false;
            }
            ifs.seekg(offset, ios::beg);
            ifs.read(body, len);
            if (ifs.good() == false)
            {
                DLOG("文件读取失败: %s", strerror(errno));
                ifs.close();
                return false;
            }
            ifs.close();
            return true;
        }
        // 从文件中读取数据
        bool read(string &body)
        {
            size_t size = this->size();
            body.resize(size);
            return read(&body[0], 0, size);
        }
        // 向文件中写入数据
        bool write(const char *body, size_t offset, size_t len)
        {
            fstream fs(_filename, ios::binary | ios::in | ios::out);
            if (fs.is_open() == false)
            {
                DLOG("文件打开失败: %s", strerror(errno));
                return false;
            }
            fs.seekp(offset, ios::beg);
            fs.write(body, len);
            if (fs.good() == false)
            {
                DLOG("文件写入失败: %s", strerror(errno));
                fs.close();
                return false;
            }
            fs.close();
            return true;
        }
        // 向文件中写入数据
        bool write(const string &body)
        {
            return write(body.c_str(), 0, body.size());
        }
        // 修改文件名称
        bool rename(const string &name)
        {
            return (::rename(_filename.c_str(), name.c_str()) == 0);
        }
        // 获取文件父目录
        static std::string parentDirectory(const string &filename)
        {
            size_t pos = filename.find_last_of('/');
            if (pos == string::npos)
                return filename;
            return filename.substr(0, pos);
        }
        // 创建文件
        static bool createFile(const string &filename)
        {
            if (FileHelper(filename).exists() == true)
                return true;
            ofstream fs(filename, ios::binary | ios::out);
            if (fs.is_open() == false)
            {
                DLOG("文件打开失败: %s", strerror(errno));
                return false;
            }
            fs.close();
            return true;
        }
        // 删除文件
        static bool removeFile(const string &filename)
        {
            return remove(filename.c_str()) == 0;
        }
        // 创建目录
        static bool createDirectory(const string &path)
        {
            size_t idx = 0, pos = 0;
            while (idx < path.size())
            {
                pos = path.find("/", idx);
                if (pos == string::npos)
                    return (mkdir(path.c_str(), 0775) == 0);
                string subpath = path.substr(0, pos);
                int ret = mkdir(subpath.c_str(), 0775);
                if (ret != 0 && errno != EEXIST)
                {
                    DLOG("目录创建失败: %s", strerror(errno));
                    return false;
                }
                idx = pos + 1;
            }
            return true;
        }
        // 删除目录
        static bool removeDirectory(const string &path)
        {
            string cmd = "rm -rf ./" + path;
            return (system(cmd.c_str()) != -1);
        }

    private:
        string _filename;
    };
};
